package nl.altenpts.net.kad;

import java.nio.ByteBuffer;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.util.*;

public class Value {
	
	public Value(byte[] key, byte[] value) {
		this.key = new Key(key);
		this.value = value;
	}
	
	public Value(byte[] key, byte[] value, PublicKey setterkey, byte[] sign) {
		this.setterkey = setterkey;
		this.key = new Key(key);
		this.value = value;
		this.settersign = sign;
	}
	
	public Value(ByteBuffer buffer) throws InvalidKeySpecException {
		byte[] bkey = new byte[buffer.getInt()];
		buffer.get(bkey);
		key = new Key(bkey);
		value = new byte[buffer.getInt()];
		buffer.get(value);
		byte[] enckey = new byte[buffer.getInt()];
		buffer.get(enckey);
		setterkey = Kademlia.enckeyToPublicKey(enckey);		
		settersign = new byte[buffer.getInt()];
		buffer.get(settersign);		
	}
	
	public ByteBuffer toByteBuffer() {
		byte[] enckey = setterkey.getEncoded();
		ByteBuffer buffer = ByteBuffer.allocate(16 + key.getArray().length + value.length + enckey.length + settersign.length);
		
		buffer.putInt(key.getArray().length);
		buffer.put(key.getArray());
		buffer.putInt(value.length);
		buffer.put(value);
		buffer.putInt(enckey.length);
		buffer.put(enckey);
		buffer.putInt(settersign.length);
		buffer.put(settersign);
		buffer.flip();
		
		return buffer;
	}
	
	public Key getHashKey() {
		return key;
	}
	
	public byte[] getKey() {
		return key.getArray();
	}
	
	public byte[] getValue() {
		return value;
	}
	
	public void setValue(byte[] newvalue) {
		value = newvalue;
	}
	
	public byte[] getSign() {
		return settersign;
	}
		
	public boolean checkSignature() {
		
		Signature signature;
		
		try {
			signature = Signature.getInstance(Kademlia.signalg);
			signature.initVerify(setterkey);
			signature.update(key.getArray());
			signature.update(value);
			return signature.verify(settersign);
		} catch (NoSuchAlgorithmException e) {
			assert(false);
			return false;
		} catch (SignatureException e) {
			return false;
		} catch (InvalidKeyException e) {
			return false;
		}
	}
	
	public void sign(KeyPair keys) throws InvalidKeyException {
		Signature signature;
			
		try {
			signature = Signature.getInstance(Kademlia.signalg);
			signature.initSign(keys.getPrivate());
			signature.update(key.getArray());
			signature.update(value);
			settersign = signature.sign();
			setterkey = keys.getPublic();
		} catch (NoSuchAlgorithmException e) {
			assert(false);
		} catch(SignatureException e) {
			assert false;
		}
	}
	
	public PublicKey getSetter() {
		return setterkey;
	}
	
	public boolean equals(Object o) {
		if( !(o instanceof Value) ) {
			return false;
		}
		Value v = (Value) o;
		if( !(setterkey.equals(v.setterkey)) ) {
			return false;
		} else if( !(Arrays.equals(v.value, value)) ) {
			return false;
		} else if ( !(key.equals(v.key)) ) {
			return false;
		} else return true;
	
	}
	
	private PublicKey setterkey;
	private byte[] settersign;
	private byte[] value;
	private Key key;
}
